/********************************************************************************
* @file    app_io_task.c
* @author  jianqiang.xue
* @version V1.1.0
* @date    2023-03-21
* @brief   IO周期任务
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>

#include "os_api.h"
#include "log.h"
#include "kv_sys.h"
#include "atcmd_slave.h"
/* Private Includes ----------------------------------------------------------*/
#include "app_main.h"
#include "ls_gpio.h"
#include "ls_syscfg.h"
#include "ls_key.h"
#include "app_io.h"
#if LS_APP_IO_TIMER_SUPPORT
/* Private Define ------------------------------------------------------------*/

/* Typedef Struct ------------------------------------------------------------*/
/* Public Enum ---------------------------------------------------------------*/
/* External Variables --------------------------------------------------------*/
/* Public Variables ----------------------------------------------------------*/
/* Private Variables ---------------------------------------------------------*/
io_task_t *g_io_task = NULL;
uint8_t g_io_task_num = 0;
uint32_t g_timer_io_time_ms = LS_APP_IO_TIMER_TIME_MS; // 软件定时器的基准时间
/****************软定时器创建****************/
OS_TIMER_DECLARE_N(app_io);

/* Publib Function Prototypes ------------------------------------------------*/
uint8_t app_io_task_create(io_task_t *task) {
    uint8_t ret = 0;
    io_task_t *io_task = g_io_task;
    io_task_t *p = NULL;
    if (g_io_task_num == 0)
        goto create;
    else {
        for (uint8_t i = 0; i < g_io_task_num; i++) {
            if (io_task->task_id == task->task_id) {
                memcpy(io_task, task, sizeof(io_task_t) - 4); // 不替换最后4字节(下一个任务地址)
                goto succeed;
            } else {
                if (io_task->next_task)
                    io_task = (io_task_t *)io_task->next_task;
                else
                    goto create;
            }
        }
    }
create: // 没有找到任务，创建新任务
    p = malloc(sizeof(io_task_t));
    if (!p) {
        ret = 1;
        goto end;
    } else {
        memcpy(p, task, sizeof(io_task_t));
        if (g_io_task_num == 0) {
            g_io_task = p;
        } else {
            io_task->next_task = (io_task_t *)p;
            io_task = (io_task_t *)p;
        }

        if (io_task->io > LS_IO_NUM - 1 || io_task->io == 0) {
            ret = 1;
            goto end;
        }

        // 判断IO是否为OUT类型
        if (g_io_cfg[io_task->io].type != IO_TYPE_OUT_PP && // 周期任务目标，会被强制设置为输出
            g_io_cfg[io_task->io].type < IO_TYPE_TIM1_CH1 && g_io_cfg[io_task->io].type > IO_TYPE_TIM2_CH4) {
            io_set_out_mode(io_task->io, IO_OUT_PP);
        }
        g_io_task_num++;
        goto succeed;

    }
succeed:
    ret = 0;
    os_timer_restart(OS_TIMER_ID(app_io), g_timer_io_time_ms);
end:
    return ret;
}

io_task_t * app_io_task_find(uint8_t task_id) {
    io_task_t *io_task = g_io_task;
    for (uint8_t i = 0; i < g_io_task_num; i++) {
        if (io_task->task_id == task_id)
            return io_task;
        else {
            if (io_task->next_task)
                io_task = (io_task_t *)io_task->next_task;
            else
                return NULL;
        }
    }
    return NULL;
}

/* Private Function Prototypes -----------------------------------------------*/
static void app_pwm_ctl(uint8_t event, bsp_pwm_t pwmx, io_task_parm_t *task) {
    switch (event) { // 0--低电平 1--高电平 2--翻转电平 3--指定亮度(0-100%) 4--翻转电平指定亮度(0-100%) 5--缓慢上升 6--缓慢下降 6--呼吸
        case 0:
            bsp_pwm_set_pulse(pwmx, 0);
            break;
        case 1:
            bsp_pwm_set_pulse(pwmx, -1);
            break;
        case 2:
            if (bsp_pwm_get_pulse(pwmx))
                bsp_pwm_set_pulse(pwmx, 0);
            else
                bsp_pwm_set_pulse(pwmx, -1);
            break;
        case 3:
            if (task == NULL) break;
            bsp_pwm_set_pulse(pwmx, bsp_pwm_pp_to_pulse(pwmx, task->target_val));
            break;
        case 4:
            if (bsp_pwm_get_pulse(pwmx))
                bsp_pwm_set_pulse(pwmx, 0);
            else {
                if (task == NULL) break;
                bsp_pwm_set_pulse(pwmx, bsp_pwm_pp_to_pulse(pwmx, task->target_val));
            }
            break;
        case 5:
            if (task == NULL) break;
            //task->target_val = task->init_val;
            if (task->target_val != task->val) {
                bsp_pwm_set_pulse(pwmx, task->val);
                task->val++;
            } else {
                //bsp_pwm_set_pulse(pwmx, task->init_val);
            }
            break;
        case 6:
            if (task == NULL) break;
            // task->target_val = task->init_val;
            if (task->target_val != task->val) {
                bsp_pwm_set_pulse(pwmx, task->val);
                task->val--;
            } else {
                //bsp_pwm_set_pulse(pwmx, task->init_val);
            }
            break;
        default:
            break;
    }
}
/**
 * @brief  操作IO
 * @param  event: 0--低电平 1--高电平 2--翻转电平 -1--无效
 * @param  io: io号
 */
static void app_io_ctl(uint8_t event, uint8_t io, io_task_parm_t *task) {
    if ((g_io_cfg[io].type == IO_TYPE_OUT_PP) || (g_io_cfg[io].type == IO_TYPE_OUT_OD)) {
        switch (event) {
            case 0:
            case 1:
                io_out(io, event);
                break;
            case 2:
                io_toggle(io);
            default:
                break;
        }
    } else if ((g_io_cfg[io].type >= IO_TYPE_TIM1_CH1) && (g_io_cfg[io].type <= IO_TYPE_TIM2_CH4)) {
        app_pwm_ctl(event, g_io_cfg[io].type-IO_TYPE_TIM1_CH1, task);
    }
}
/**
 * @brief  [软定时器] IO_TASK 控制IO操作
 */
static void timer_app_io_cb(void const *arg) {
    // if (g_io.flag.save_support == 1) {
    //     if (g_io.flag.write_in == 1) {
    //         g_io.flag.write_in = 0;
    //         // main_send_signal(SIGNAL_KV_WRITE_APP_IO_INFO);
    //     }
    // }

    if (g_io_task == NULL) {
        OS_TIMER_STOP(app_io);
        return;
    }
    uint8_t not_valid_cnt = 0;
    io_task_t *io_task = g_io_task;
    for (uint8_t i = 0; i < g_io_task_num; i++) {
        if (io_task->is_valid && io_task->io != 0xFF) {
            io_task->countdown += g_timer_io_time_ms;
            if (io_task->step == 0) {
                if (io_task->start_time == 0)
                    goto step1;

                if (io_task->countdown >= io_task->start_time) {
                    // app_io_ctl(io_task->start_event, io_task->io, &(io_task->start_parm));
                    io_task->step = 1;
                }
            } else if (io_task->step == 1) {
step1:
                if (io_task->start_parm.target_num == 0)
                    goto step2;

                if (io_task->start_parm.cnt != io_task->start_parm.target_num) {
                    if (io_task->countdown % io_task->start_parm.time == 0) {

                        app_io_ctl(io_task->start_parm.event, io_task->io, &(io_task->start_parm));

                        if (io_task->start_parm.event == 5) {
                            if (io_task->start_parm.target_val == io_task->start_parm.val) {
                                io_task->start_parm.cnt++;
                                io_task->start_parm.val = io_task->start_parm.init_val;
                                //LOGD("step1");
                            }
                        } else if (io_task->start_parm.event == 6) {
                            if (io_task->start_parm.target_val == io_task->start_parm.val) {
                                io_task->start_parm.cnt++;
                                io_task->start_parm.val = io_task->start_parm.init_val;
                            }
                        } else {
                            io_task->start_parm.cnt++;
                        }

                    }
                } else {
                    io_task->step = 2;
                }
            } else if (io_task->step == 2) {
step2:
                if (io_task->stop_parm.target_num == 0)
                    goto step3;

                if (io_task->stop_parm.cnt != io_task->stop_parm.target_num) {
                    if (io_task->countdown % io_task->stop_parm.time == 0) {
                        app_io_ctl(io_task->stop_parm.event, io_task->io, &(io_task->stop_parm));
                        if (io_task->stop_parm.event == 5) {
                            if (io_task->stop_parm.target_val == io_task->stop_parm.val) {
                                io_task->stop_parm.val = io_task->stop_parm.init_val;
                                io_task->stop_parm.cnt++;
                            }
                        } else if (io_task->stop_parm.event == 6) {
                            if (io_task->stop_parm.target_val == io_task->stop_parm.val) {
                                io_task->stop_parm.val = io_task->stop_parm.init_val;
                                io_task->stop_parm.cnt++;
                                //LOGD("step2");
                            }
                        } else {
                            io_task->stop_parm.cnt++;
                        }
                    }
                } else {
                    io_task->step = 3;
                }
            } else if (io_task->step == 3) { // 当步骤3完成时，清除计数器
step3:
                if (io_task->stop_time == 0)
                    goto step5;
                io_task->step = 4;
                io_task->countdown = 0;
            } else if (io_task->step == 4) {
                if ((io_task->countdown >= io_task->stop_time)) {
                    //app_io_ctl(io_task->stop_event, pin_id, &(io_task->stop_parm));
                    io_task->step = 5;
                }
            } else {
step5:
                if (io_task->is_repeat != 0) {
                    io_task->is_repeat --;
                    if (io_task->is_repeat == 0) {
                        io_task->is_valid = 0;
                        g_io.flag.write_in = 1;
                    }
                }
                io_task->countdown = 0;
                io_task->start_parm.cnt = 0;
                io_task->stop_parm.cnt = 0;
                io_task->step = 0;
            }
        } else {
            not_valid_cnt++;
        }
        if(io_task->next_task)
            io_task = (io_task_t *)io_task->next_task;
        else
            break;
        if (g_io_task_num == not_valid_cnt) { // 当任务都无效时，停止软定时器
            OS_TIMER_STOP(app_io);
        }
    }
    //LOGD("id:%d,%d", io_task->io, g_io_task_num);
}

uint8_t app_io_task_init(void) {
    uint32_t timer_ret = 0;
    // 创建软定时器 IO任务，用于定时执行任务或者写入flash。
    OS_TIMER_CREATE(app_io, OS_TIMER_PERIODIC);
    return 0;
}

#if ATCMD_EN
extern os_timer_id OS_TIMER_ID(app_io);

// 设置周期任务的基准时间 =<ms>
static int atcmd_set_io_timer_ms(atcmd_pack_t *pack) {
    uint32_t argc[1] = {0};
    char buff[40] = {0};
    uint8_t len = 0;
    pack->argc = sscanf((char*)(pack->data), "%u", &argc[0]);
    if (pack->argc != 1) return -1;
    // 先停止周期任务
    OS_TIMER_STOP(app_io);
    g_timer_io_time_ms = argc[0];
    if (argc[0]) {
        if (os_timer_restart(OS_TIMER_ID(app_io), argc[0]) != OS_OK) {
            len = snprintf(buff, 40, "+IO_TIMER_MS=io timer restart fail\r\n");
            pack->reply((uint8_t*)buff, len);
            return -2;
        }
    } else {
        if (os_timer_stop(OS_TIMER_ID(app_io)) != OS_OK) {
            len = snprintf(buff, 40, "+IO_TIMER_MS=io timer stop fail\r\n");
            pack->reply((uint8_t*)buff, len);
            return -3;
        }
    }
    len = snprintf(buff, 40, "+IO_TIMER_MS=OK\r\n");
    pack->reply((uint8_t*)buff, len);
    return 0;
}

// static int atcmd_set_task_func_help(atcmd_pack_t *pack) {
//     char buff[64] = {0};
//     uint8_t len = 0;
//     strcpy(buff, "help_set_task:=<task_id>,<IO_ID(hex,use IO_11,0x800)>,");
//     pack->reply((uint8_t*)buff, strlen(buff));
//     strcpy(buff, "<is_valid>,<is_repeat>,");
//     pack->reply((uint8_t*)buff, strlen(buff));
//     strcpy(buff, "<start_t>,<start_t2>,<start_evt>,<start_target_num>,");
//     pack->reply((uint8_t*)buff, strlen(buff));
//     strcpy(buff, "<stop_t>,<stop_t2>,<stop_evt>,<stop_target_num>\r\n");
//     pack->reply((uint8_t*)buff, strlen(buff));
//     strcpy(buff, AT_OK);
//     pack->reply((uint8_t*)buff, strlen(buff));
//     return 0;
// }
// 设置周期任务 =<task_id>,<IO_ID>,<is_valid>,<is_repeat>,
// <start_time>,<start_time2>,<start_event>,<start_target_num>,<start_target_val>,<start_init_val>
// <stop_time>,<stop_time2>,<stop_event>,<stop_target_num>,<stop_target_val>,<stop_init_val>
static int atcmd_set_io_task_func(atcmd_pack_t *pack) {
    char buff[35] = {0};
    uint8_t len = 0;
    int8_t ret = 0;
    uint8_t arg_cnt = 0; // 记录扩展变量使用数量
    if (!g_io.flag.timer_support) {
        len = snprintf(buff, 30, "+IO_TASK:NON SUPPORT\r\n");
        pack->reply((uint8_t*)buff, len);
        ret = -1;
        goto end;
    }
    uint32_t argc[16] = {0};
    pack->argc = sscanf((char*)(pack->data), "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
                        &argc[0], &argc[1], &argc[2], &argc[3],
                        &argc[4], &argc[5], &argc[6], &argc[7],
                        &argc[8], &argc[9], &argc[10], &argc[11],
                        &argc[12], &argc[13], &argc[14], &argc[15]);
    if (pack->argc != 16) {
        len = snprintf(buff, 35, "+IO_TASK:ARGCERR num %u!=16\r\n", pack->argc);
        pack->reply((uint8_t*)buff, len);
        ret = -2;
        goto end;
    }
    if (argc[1] == 0 || argc[1] > LS_IO_NUM - 1) {
        len = snprintf(buff, 35, "+IO_TASK:ARGCERR no io %u\r\n", argc[1]);
        pack->reply((uint8_t*)buff, len);
        ret = -3;
        goto end;
    }
    io_task_t io_task;
    memset(&io_task, 0, sizeof(io_task_t));
    io_task.task_id               = argc[0];
    io_task.io                   = argc[1];
    io_task.is_valid              = argc[2];
    io_task.is_repeat             = argc[3];
    io_task.start_time            = argc[4];
    io_task.start_parm.time       = argc[5];
    io_task.start_parm.event      = argc[6];
    io_task.start_parm.target_num = argc[7];
    io_task.start_parm.target_val = argc[8];
    io_task.start_parm.init_val   = argc[9];
    io_task.stop_time             = argc[10];
    io_task.stop_parm.time        = argc[11];
    io_task.stop_parm.event       = argc[12];
    io_task.stop_parm.target_num  = argc[13];
    io_task.stop_parm.target_val  = argc[14];
    io_task.stop_parm.init_val    = argc[15];

    io_task.start_parm.val = io_task.start_parm.init_val;
    io_task.stop_parm.val = io_task.stop_parm.init_val;
    OS_TIMER_STOP(app_io);
    if (app_io_task_create(&io_task)) { // 创建失败
        ret = -3;
        len = snprintf(buff, 30, "+IO_TASK:ERROR\r\n");
        pack->reply((uint8_t*)buff, len);
    } else {
        if (os_timer_restart(OS_TIMER_ID(app_io), g_timer_io_time_ms) != OS_OK) {
            len = snprintf(buff, 30, "+IO_TASK:io timer restart fail\r\n");
            pack->reply((uint8_t*)buff, len);
        } else {
            len = snprintf(buff, 30, "+IO_TASK:OK\r\n");
            pack->reply((uint8_t*)buff, len);
        }
    }
end:
    return ret;
}
// 得到周期任务 =<task_id>,<IO_ID>,<is_valid>,<is_repeat>,<start_time>,<start_time2>,<start_event>,<start_target_num>,
// <stop_time>,<stop_time2>,<stop_event>,<stop_target_num>
static int atcmd_get_io_task_func(atcmd_pack_t *pack) {
    char buff[80] = {0};
    uint8_t len = 0;
    io_task_t *io_task = g_io_task;
    len = snprintf(buff, 80, "+IO_TASK:");
    pack->reply((uint8_t *)buff, len);
    for (uint8_t i = 0; i < g_io_task_num; i++) {
        snprintf(buff, 80, "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u|",
        io_task->task_id, io_task->io, io_task->is_valid, io_task->is_repeat,
        io_task->start_time, io_task->start_parm.time, io_task->start_parm.event, io_task->start_parm.target_num, io_task->start_parm.target_val, io_task->start_parm.init_val,
        io_task->stop_time, io_task->stop_parm.time, io_task->stop_parm.event, io_task->stop_parm.target_num, io_task->stop_parm.target_val, io_task->stop_parm.init_val);
        pack->reply((uint8_t *)buff, strlen(buff));
        if(io_task->next_task)
            io_task = (io_task_t *)io_task->next_task;
        else {
            break;
        }
    }
    pack->reply((uint8_t *)"\r\n", 2);
    return 0;
}

static int atcmd_del_io_task_func(atcmd_pack_t *pack) {
    char buff[30] = {0};
    uint8_t len = 0;
    uint32_t argc[1] = {0};
    uint8_t timer_state = os_timer_is_running(OS_TIMER_ID(app_io));
    OS_TIMER_STOP(app_io);
    pack->argc = sscanf((char*)(pack->data), "%d", &argc[0]);
    if (pack->argc != 1) {
        len = snprintf(buff, 30, "+IO_TASK_DEL:ARGCERR\r\n");
        pack->reply((uint8_t *)buff, len);
        return -1;
    }
    io_task_t *io_task = g_io_task;
    io_task_t *io_task_old = g_io_task; // 记录上一个节点地址
    for (uint8_t i = 0; i < g_io_task_num; i++) {
        if (io_task->task_id == argc[0]) {
            if (i == 0) { // 首节点
                void *temp = io_task->next_task;
                free(io_task);
                g_io_task = (io_task_t *)temp;
                g_io_task_num--;
            } else {
                void *temp = io_task->next_task;
                free(io_task);
                io_task_old->next_task = (io_task_t *)temp;
                g_io_task_num--;
            }
            break;
        }
        if (io_task->next_task) {
            io_task_old = io_task;
            io_task = (io_task_t *)io_task->next_task;
        } else
            break;
    }
    if (g_io_task_num == 0)
        g_io_task = NULL;
    else {
        if (timer_state) { // 如果周期定时器运行，则恢复
            OS_TIMER_START(app_io, g_timer_io_time_ms);
        }
    }
    len = snprintf(buff, 30, "+IO_TASK_DEL:OK\r\n");
    pack->reply((uint8_t *)buff, len);
    return 0;
}

static int atcmd_del_all_io_task_func(atcmd_pack_t *pack) {
    char buff[30] = {0};
    uint8_t len = 0;
    io_task_t *io_task = g_io_task;
    OS_TIMER_STOP(app_io);
    for (uint8_t i = 0; i < g_io_task_num; i++) {
        void *temp = io_task->next_task;
        free(io_task);
        g_io_task = (io_task_t *)temp;
        g_io_task_num--;
        if (g_io_task) {
            io_task = (io_task_t *)io_task->next_task;
        } else
            break;
    }
    g_io_task = NULL;
    len = snprintf(buff, 30, "+IO_TASK_DEL_ALL:OK\r\n");
    pack->reply((uint8_t *)buff, len);
    return 0;
}

ATCMD_INIT("AT+IO_TIMER_MS=", atcmd_set_io_timer_ms);
ATCMD_INIT("AT+IO_TASK=", atcmd_set_io_task_func);
// ATCMD_INIT("AT+IO_TASK=?", atcmd_set_task_func_help);
ATCMD_INIT("AT+IO_TASK?", atcmd_get_io_task_func);
ATCMD_INIT("AT+IO_TASK_DEL=", atcmd_del_io_task_func);
ATCMD_INIT("AT+IO_TASK_DEL_ALL", atcmd_del_all_io_task_func);
#endif
#endif
